Skip to content

fix(bind): restore []string values for map[string]interface{} duplicates#2982

Closed
leno23 wants to merge 1 commit into
labstack:v4from
leno23:fix/multipart-map-interface-slice-binding
Closed

fix(bind): restore []string values for map[string]interface{} duplicates#2982
leno23 wants to merge 1 commit into
labstack:v4from
leno23:fix/multipart-map-interface-slice-binding

Conversation

@leno23

@leno23 leno23 commented May 25, 2026

Copy link
Copy Markdown

Summary

  • Fix regression when binding multipart form data with duplicate field names to map[string]interface{}
  • Store a single value as string and multiple values as []string

Problem

Since v4.13.0, binding duplicate multipart fields like two ima_slice values to map[string]interface{} only kept the first value. Applications expecting a slice silently broke.

This regressed after #2656, which intended to preserve pre-v4.12.0 single-string behavior but always bound v[0].

Fix

For map[string]interface{} / map[string]any:

  • one value → string
  • multiple values → []string

Test plan

  • Updated TestDefaultBinder_bindDataToMap
  • Added TestBindMultipartFormToMapInterface
  • go test ./... -run 'TestDefaultBinder_bindDataToMap|TestBindMultipartFormToMapInterface'

Fixes #2731

When binding multipart/form-data to map[string]interface{}, store a single
value as string and multiple values as []string. This matches the behavior
before v4.13.0 and the intent of labstack#2656.

Fixes labstack#2731

Co-authored-by: Cursor <cursoragent@cursor.com>
@vishr

vishr commented Jun 13, 2026

Copy link
Copy Markdown
Member

Heads-up for whoever reviews this: binding map[string]interface{} to the full []string (rather than the first value) is the behavior that was intentionally reverted in #2656 (which undid #2554) after it broke users who relied on the first-value semantics. The current // To maintain backward compatibility, we always bind to the first string value comment documents that decision.

This PR re-introduces the slice behavior for the duplicate-key case, so it would re-break the same users #2656 was protecting. That may well be the right call for v5 (a major version is the place to change it) — just flagging that it's a deliberate backward-compat reversal, not a pure bugfix, so the decision is made consciously and noted in the v5 migration guide if accepted.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a regression in Echo’s default binder where duplicate multipart/form-data fields bound into map[string]interface{}/map[string]any would incorrectly keep only the first value, restoring the intended behavior (single value as string, multiple values as []string).

Changes:

  • Update DefaultBinder.bindData map binding to store []string when a key has multiple values for map[string]interface{}.
  • Update existing map-binding expectations in TestDefaultBinder_bindDataToMap.
  • Add a multipart/form-data regression test covering duplicate field names bound into map[string]interface{}.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
bind.go Restores multi-value binding behavior for map[string]interface{} when values are duplicated.
bind_test.go Updates map-binding tests and adds a multipart regression test for duplicate fields.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread bind.go
Comment on lines 183 to +187
} else if isElemInterface {
// To maintain backward compatibility, we always bind to the first string value
// and not the slice of strings when dealing with map[string]interface{}{}
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
if len(v) == 1 {
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
} else {
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v))
@aldas

aldas commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

This comment explains when and why this was changed #2731 (comment) I do not think this should be merged.

@vishr

vishr commented Jun 16, 2026 via email

Copy link
Copy Markdown
Member

@aldas aldas closed this Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants